/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.moneydance.modules.features.mdcsvimporter;

import com.moneydance.apps.md.model.Account;
import com.moneydance.apps.md.model.RootAccount;
import java.awt.Color;
import java.awt.event.ItemEvent;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import javax.swing.JFileChooser;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

/**
 *
 * @author miki
 */
public class ImportDialog
   extends javax.swing.JDialog
{
   private File selectedFile;
   private CSVData csvData;
   private TransactionReader transactionReader;
   private Main main;

   public ImportDialog( Main main )
   {
      super( main.getMoneydanceWindow(), true );
      initComponents();

      textFilename.getDocument().addDocumentListener( new DocumentListener()
      {
         public void insertUpdate( DocumentEvent e )
         {
            textFilenameChanged();
         }

         public void removeUpdate( DocumentEvent e )
         {
            textFilenameChanged();
         }

         public void changedUpdate( DocumentEvent e )
         {
            textFilenameChanged();
         }
      } );

      this.main = main;
      fillAccountCombo( main );

      checkDeleteFile.setSelected( Settings.getBoolean( "delete.file" ) );

      fileChanged();
   }

   private void fillAccountCombo( Main main )
   {
      RootAccount rootAccount = main.getRootAccount();
      comboAccount.removeAllItems();

      fillAccountCombo_( rootAccount );

      if ( comboAccount.getItemCount() > 0 )
      {
         comboAccount.setSelectedIndex( Settings.getInteger( "selected.account", 0 ) );
      }
   }

   private void fillAccountCombo_( Account parentAccount )
   {
      for ( int i = 0; i < parentAccount.getSubAccountCount(); ++i )
      {
         Account account = parentAccount.getSubAccount( i );
         if ( account.isRegisterAccount() )
         {
            comboAccount.addItem( account );
         }
         else
         {
            fillAccountCombo_( account );
         }
      }
   }

   /** This method is called from within the constructor to
    * initialize the form.
    * WARNING: Do NOT modify this code. The content of this method is
    * always regenerated by the Form Editor.
    */
   @SuppressWarnings("unchecked")
   // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
   private void initComponents() {

      jLabel3 = new javax.swing.JLabel();
      lblSelectFile = new javax.swing.JLabel();
      textFilename = new javax.swing.JTextField();
      btnBrowse = new javax.swing.JButton();
      checkDeleteFile = new javax.swing.JCheckBox();
      btnClose = new javax.swing.JButton();
      btnProcess = new javax.swing.JButton();
      lblAccount = new javax.swing.JLabel();
      comboAccount = new javax.swing.JComboBox();
      lblMessage = new javax.swing.JLabel();
      lblFileFormat = new javax.swing.JLabel();
      comboFileFormat = new javax.swing.JComboBox();
      lblDateFormat = new javax.swing.JLabel();
      comboDateFormat = new javax.swing.JComboBox();

      jLabel3.setText("jLabel3");

      setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
      setTitle("Import CSV File");
      setName("importDialog"); // NOI18N
      setResizable(false);

      lblSelectFile.setText("Select File:");

      btnBrowse.setText("...");
      btnBrowse.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            btnBrowseActionPerformed(evt);
         }
      });

      checkDeleteFile.setText("Securely erase file after processing.");
      checkDeleteFile.setToolTipText("If checked, the specified file will be securely erased (first overwritten, then deleted) after successful processing.");

      btnClose.setText("Close");
      btnClose.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            btnCloseActionPerformed(evt);
         }
      });

      btnProcess.setText("Process");
      btnProcess.setEnabled(false);
      btnProcess.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            btnProcessActionPerformed(evt);
         }
      });

      lblAccount.setText("Select Account:");

      comboAccount.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));

      lblMessage.setForeground(new java.awt.Color(255, 0, 51));
      lblMessage.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
      lblMessage.setText("jLabel4");
      lblMessage.setOpaque(true);

      lblFileFormat.setText("File Format:");

      comboFileFormat.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
      comboFileFormat.addItemListener(new java.awt.event.ItemListener() {
         public void itemStateChanged(java.awt.event.ItemEvent evt) {
            fileFormatChanged(evt);
         }
      });

      lblDateFormat.setText("Date Format:");

      comboDateFormat.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));

      org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
      getContentPane().setLayout(layout);
      layout.setHorizontalGroup(
         layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
         .add(layout.createSequentialGroup()
            .addContainerGap()
            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
               .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                  .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                     .add(lblSelectFile)
                     .add(lblFileFormat))
                  .add(29, 29, 29)
                  .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                     .add(layout.createSequentialGroup()
                        .add(textFilename, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(btnBrowse, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 40, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                     .add(comboFileFormat, 0, 320, Short.MAX_VALUE)))
               .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                  .add(btnProcess)
                  .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                  .add(btnClose))
               .add(layout.createSequentialGroup()
                  .add(103, 103, 103)
                  .add(comboDateFormat, 0, 320, Short.MAX_VALUE))
               .add(lblDateFormat)
               .add(layout.createSequentialGroup()
                  .add(checkDeleteFile)
                  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 168, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
               .add(lblMessage, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 423, Short.MAX_VALUE)
               .add(layout.createSequentialGroup()
                  .add(lblAccount)
                  .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                  .add(comboAccount, 0, 321, Short.MAX_VALUE)))
            .add(12, 12, 12))
      );
      layout.setVerticalGroup(
         layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
         .add(layout.createSequentialGroup()
            .addContainerGap()
            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
               .add(lblSelectFile)
               .add(textFilename, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
               .add(btnBrowse))
            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
               .add(comboFileFormat, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
               .add(lblFileFormat))
            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
               .add(lblDateFormat)
               .add(comboDateFormat, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
            .add(18, 18, 18)
            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
               .add(lblAccount)
               .add(comboAccount, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
            .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
            .add(checkDeleteFile, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 23, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
            .add(lblMessage, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 16, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
               .add(btnClose)
               .add(btnProcess))
            .addContainerGap())
      );

      pack();
   }// </editor-fold>//GEN-END:initComponents

    private void btnBrowseActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_btnBrowseActionPerformed
    {//GEN-HEADEREND:event_btnBrowseActionPerformed
       JFileChooser dialog = new JFileChooser();
       dialog.setFileHidingEnabled( true );
       dialog.setDialogTitle( "Select text file" );
       dialog.setCurrentDirectory(
          new File( Settings.get( "last.directory",
          dialog.getCurrentDirectory().getAbsolutePath() ) ) );
       dialog.addChoosableFileFilter( new FileFilter()
       {
          @Override
          public boolean accept( File f )
          {
             return f.isDirectory() || f.getName().endsWith( ".csv" );
          }

          @Override
          public String getDescription()
          {
             return "Formatted Text File (*.csv)";
          }
       } );
       if ( dialog.showDialog( this, "Select" ) == JFileChooser.APPROVE_OPTION )
       {
          selectedFile = dialog.getSelectedFile();
          Settings.set( "last.directory", dialog.getCurrentDirectory().getAbsolutePath() );
          textFilename.setText( selectedFile.getPath() );
          fileChanged();
       }
}//GEN-LAST:event_btnBrowseActionPerformed

    private void btnCloseActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_btnCloseActionPerformed
    {//GEN-HEADEREND:event_btnCloseActionPerformed
       this.setVisible( false );
    }//GEN-LAST:event_btnCloseActionPerformed

    private void btnProcessActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_btnProcessActionPerformed
    {//GEN-HEADEREND:event_btnProcessActionPerformed
       Settings.setYesNo( "delete.file", checkDeleteFile.isSelected() );
       Settings.setInteger( "selected.account", comboAccount.getSelectedIndex() );

       TransactionReader reader = (TransactionReader) comboFileFormat.getSelectedItem();
       reader.setDateFormat( (String) comboDateFormat.getSelectedItem() );

       try
       {
          reader.parse( csvData, (Account) comboAccount.getSelectedItem() );
       }
       catch ( IOException x )
       {
          JOptionPane.showMessageDialog( rootPane, "There was a problem importing "
             + " selected file, probably because the file format was wrong. Some items " +
             "might have been added to your account.",
             "Error Importing File",
             JOptionPane.ERROR_MESSAGE );
          return;
       }

       if ( checkDeleteFile.isSelected() )
       {
          try
          {
             SecureFileDeleter.delete( selectedFile );
          }
          catch ( IOException x )
          {
             JOptionPane.showMessageDialog( rootPane, "The file was imported properly, "
                + "however it could not be erased as requested.", "Cannot Delete File",
                JOptionPane.ERROR_MESSAGE );
             return;
          }
       }

       if ( !Settings.getBoolean( "success.dialog.shown", false ) )
       {
          Settings.setYesNo( "success.dialog.shown", true );
          JOptionPane.showMessageDialog( rootPane,
             "The file was imported properly. \n\n"
             + "You can view the imported items when you open the account you have \n"
             + "selected and click on the 'downloaded transactions' message at the \n"
             + "bottom of the screen.",
             "Import Successful", JOptionPane.INFORMATION_MESSAGE );
       }

       setVisible( false );
    }//GEN-LAST:event_btnProcessActionPerformed

    private void fileFormatChanged(java.awt.event.ItemEvent evt)//GEN-FIRST:event_fileFormatChanged
    {//GEN-HEADEREND:event_fileFormatChanged
       if ( evt.getStateChange() == ItemEvent.SELECTED )
       {
          TransactionReader reader;
          try
          {
             reader = (TransactionReader) evt.getItem();
          }
          catch ( ClassCastException x )
          {
             reader = null;
          }
          if ( reader != null )
          {
             String[] formats = reader.getSupportedDateFormats();

             comboDateFormat.removeAllItems();
             for ( String s : formats )
             {
                comboDateFormat.addItem( s );
             }

             if ( formats.length == 0 )
             {
                comboDateFormat.addItem( "Date format not recognized" );
                comboDateFormat.setEnabled( false );
             }
             else if ( formats.length == 1 )
             {
                comboDateFormat.setSelectedIndex( 0 );
                comboDateFormat.setEnabled( false );
             }
             else
             {
                comboDateFormat.setEnabled( true );
                comboDateFormat.setSelectedItem( reader.getDateFormat() );
             }
          }
       }
    }//GEN-LAST:event_fileFormatChanged
   // Variables declaration - do not modify//GEN-BEGIN:variables
   private javax.swing.JButton btnBrowse;
   private javax.swing.JButton btnClose;
   private javax.swing.JButton btnProcess;
   private javax.swing.JCheckBox checkDeleteFile;
   private javax.swing.JComboBox comboAccount;
   private javax.swing.JComboBox comboDateFormat;
   private javax.swing.JComboBox comboFileFormat;
   private javax.swing.JLabel jLabel3;
   private javax.swing.JLabel lblAccount;
   private javax.swing.JLabel lblDateFormat;
   private javax.swing.JLabel lblFileFormat;
   private javax.swing.JLabel lblMessage;
   private javax.swing.JLabel lblSelectFile;
   private javax.swing.JTextField textFilename;
   // End of variables declaration//GEN-END:variables

   private void textFilenameChanged()
   {
      File newFile = new File( textFilename.getText() );

      if ( !newFile.equals( selectedFile ) )
      {
         selectedFile = newFile;
         fileChanged();
      }
   }

   private void fileChanged()
   {
      String message = null;
      boolean error = false;

      // see if the file is selected
      if ( selectedFile == null || !selectedFile.exists() || !selectedFile.isFile() )
      {
         message = "Please select a valid file.";
         error = true;
      }

      // try reading the file
      if ( !error )
      {
         try
         {
            CSVReader csvReader = new CSVReader( new FileReader( selectedFile ) );
            csvData = new CSVData( csvReader );
         }
         catch ( Throwable x )
         {
            error = true;
            message = "Error reading file.";
            Logger.getLogger( ImportDialog.class.getName() ).log( Level.SEVERE, null, x );
         }
      }

      // detect file format
      if ( !error )
      {
         TransactionReader[] fileFormats =
            TransactionReader.getCompatibleReaders( csvData );

         comboFileFormat.removeAllItems();
         for ( TransactionReader reader : fileFormats )
         {
            comboFileFormat.addItem( reader );
         }

         if ( fileFormats.length == 0 )
         {
            comboFileFormat.addItem( "Format not recognized" );
            comboFileFormat.setEnabled( false );
            comboDateFormat.setEnabled( false );
            error = true;
            message = "Unsupported CSV file format.";
         }
         else if ( fileFormats.length == 1 )
         {
            comboFileFormat.setSelectedIndex( 0 );
            comboFileFormat.setEnabled( false );
         }
         else
         {
            comboFileFormat.setEnabled( true );
         }
      }
      else
      {
         comboFileFormat.removeAllItems();
         comboFileFormat.addItem( "Format not recognized" );
         comboFileFormat.setEnabled( false );
      }

      if ( !error )
      {
         TransactionReader reader = (TransactionReader) comboFileFormat.getSelectedItem();
         String[] formats = reader.getSupportedDateFormats();

         comboDateFormat.removeAllItems();
         for ( String s : formats )
         {
            comboDateFormat.addItem( s );
         }

         if ( formats.length == 0 )
         {
            comboDateFormat.addItem( "Date format not recognized" );
            comboDateFormat.setEnabled( false );
            error = true;
            message = "Cannot recognize date format used in the file.";
         }
         else if ( formats.length == 1 )
         {
            comboDateFormat.setSelectedIndex( 0 );
            comboDateFormat.setEnabled( false );
         }
         else
         {
            comboDateFormat.setEnabled( true );
            comboDateFormat.setSelectedItem( reader.getDateFormat() );
         }
      }
      else
      {
         comboDateFormat.removeAllItems();
         comboDateFormat.addItem( "Date format not recognized" );
         comboDateFormat.setEnabled( false );
      }

      btnProcess.setEnabled( !error );
      if ( error )
      {
         csvData = null;
      }
      if ( message != null )
      {
         lblMessage.setVisible( true );
         lblMessage.setText( message );
         lblMessage.setForeground( new Color( 255, 0, 51 ) );
      }
      else
      {
         lblMessage.setVisible( false );
      }
   }
}
